home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume11 / mush5.7 / part10 < prev    next >
Encoding:
Internet Message Format  |  1987-09-19  |  37.4 KB

  1. Subject:  v11i060:  Mail user's shell, Part10/12
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: island!argv@Sun.COM (Dan Heller)
  7. Posting-number: Volume 11, Issue 60
  8. Archive-name: mush5.7/Part10
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 10 (of 12)."
  17. # Contents:  mail.c
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'mail.c' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'mail.c'\"
  21. else
  22. echo shar: Extracting \"'mail.c'\" \(35676 characters\)
  23. sed "s/^X//" >'mail.c' <<'END_OF_FILE'
  24. X/* @(#)mail.c     (c) copyright 1986 (Dan Heller) */
  25. X
  26. X#include "mush.h"
  27. X
  28. X/*
  29. X * mail.c --
  30. X *    do_mail()     invoked from within mail.  see function for description.
  31. X *    abort_mail()    suntools specific: resets panel items and so forth.
  32. X *    start_file()      creates the editing file and reset signal catching.
  33. X *    mail_someone()    called from do_mail() or from the shell.
  34. X *    add_to_letter()    adds the next line to letter --determine ~ escapes.
  35. X *    finish_up_letter()  prompts for Cc:, verifies user really wants to send
  36. X *    send_it()        invokes mailer, sends to record file, adds signature,
  37. X *            fortune, expands aliases, adds own_hdrs.
  38. X *    rm_edfile()    signals are directed here. remove letter, longjmp
  39. X *
  40. X * The flow of control in this file is NOT obvious to allow for both text
  41. X * and suntools _event driven_ attributes.  In text, the flow is far more
  42. X * obvious because it is sequential. In suntools, each function is called
  43. X * from outside this modual.  Keystrokes are interpreted individually and
  44. X * queued up in "rite.c".  select.c calls add_to_letter when a \n is entered
  45. X * passing the string stored in rite.c.  If you're trying to follow the flow
  46. X * of control for suntools, keep the event drivers in mind and follow select.c
  47. X * and rite.c
  48. X */
  49. X#define TO_FIELD    1
  50. X#define SUBJECT        2
  51. X#define CC_FIELD    3
  52. X#define BC_FIELD    4
  53. X
  54. Xstatic char Subject[BUFSIZ], To[BUFSIZ], Cc[BUFSIZ], Bcc[BUFSIZ];
  55. Xstatic char edfile[MAXPATHLEN], in_reply_to[256];
  56. Xstatic int killme, in_editor;
  57. Xstatic long flags;
  58. Xstatic int (*oldhup)(), (*oldterm)(), (*oldint)(), (*oldquit)();
  59. Xstatic void send_it();
  60. Xstatic FILE *fp;
  61. Xstatic jmp_buf cntrl_c_buf;
  62. X
  63. X/* argc, and argv could be null if coming from compose */
  64. Xdo_mail(n, argv)
  65. Xregister int n;   /* no need for "argc", so use the space for a variable */
  66. Xregister char **argv;
  67. X{
  68. X    char firstchar = (argv)? **argv: 'm';
  69. X    char list[MAXMSGS_BITS];
  70. X    register char *to = NULL, *cc = NULL, *subj = NULL;
  71. X    register int flgs = 0;
  72. X
  73. X    if (ison(glob_flags, IS_GETTING)) {
  74. X    print("You must finish the letter you are editing first.\n");
  75. X    return -1;
  76. X    }
  77. X    turnon(flgs, NO_IGNORE); /* if we include a message, include all hdrs */
  78. X
  79. X    clear_msg_list(list);
  80. X    if (do_set(set_options, "autoedit"))
  81. X    turnon(flgs, EDIT);
  82. X#ifdef VERBOSE_ARG
  83. X    if (do_set(set_options, "verbose"))
  84. X    turnon(flgs, VERBOSE);
  85. X#endif VERBOSE_ARG
  86. X    if (do_set(set_options, "autosign"))
  87. X    turnon(flgs, SIGN);
  88. X    if (lower(firstchar) == 'r' && do_set(set_options, "autoinclude"))
  89. X    turnon(flgs, INCLUDE), set_msg_bit(list, current_msg);
  90. X    while (argv && *argv && *++argv && **argv == '-') {
  91. X    n = 1;
  92. X    while (n && argv[0][n])
  93. X        switch (argv[0][n]) {
  94. X#ifdef VERBOSE_ARG
  95. X        case 'v': turnon(flgs, VERBOSE); n++; break;
  96. X#endif VERBOSE_ARG
  97. X        case 'e': turnon(flgs, EDIT); n++;
  98. X        when 'F': turnon(flgs, DO_FORTUNE); n++;
  99. X        when 'i': case 'h': case 'f': {
  100. X            int m;
  101. X            if (!msg_cnt) {
  102. X            print("No message to include!\n");
  103. X            return -1;
  104. X            }
  105. X            if (argv[0][n] == 'i')
  106. X            turnon(flgs, INCLUDE);
  107. X            else if (argv[0][n] == 'h')
  108. X            turnon(flgs, INCLUDE_H);
  109. X            else if (argv[0][n] == 'f')
  110. X            turnon(flgs, FORWARD);
  111. X            /* "-i 3-5" or "-i3-5"  Consider the latter case first */
  112. X            if (!argv[0][++n])
  113. X            argv++, n = 0;
  114. X            (*argv) += n;
  115. X            m = get_msg_list(argv, list);
  116. X            (*argv) -= n;
  117. X            if (m == -1)
  118. X            return -1;
  119. X            /* if there were args, then go back to the first char
  120. X             * in the next argv
  121. X             */
  122. X            if (m)
  123. X            n = 0;
  124. X            if (!n) /* n may be 0 from above! */
  125. X            argv += (m-1);
  126. X        }
  127. X        otherwise:
  128. X            if (argv[0][n] != '?')
  129. X            wprint("%c: unknown option\n", argv[0][n]);
  130. X            wprint("available options\n");
  131. X#ifdef VERBOSE_ARG
  132. X            wprint("v      verbose (passed to mail delivery system)\n");
  133. X#endif VERBOSE_ARG
  134. X            wprint("e      immediately enter editor (autoedit)\n");
  135. X            wprint("F      add fortune to the end of message.\n");
  136. X            wprint("i [msg#'s]   include msg_list into letter.\n");
  137. X            wprint("h [msg#'s]   include msg_list with headers.\n");
  138. X            wprint("f [msg#'s]   forward msg_list (not indented).\n");
  139. X            return -1;
  140. X        }
  141. X    }
  142. X    *in_reply_to = *To = *Subject = *Cc = *Bcc = 0;
  143. X    if (lower(firstchar) == 'r') {
  144. X    char buf[BUFSIZ], *p;
  145. X    to = reply_to(current_msg, (firstchar == 'R'), To);
  146. X    if (firstchar == 'R') {
  147. X        cc = cc_to(current_msg, Cc);
  148. X        if (do_set(set_options, "fixaddr"))
  149. X        fix_addresses(To, Cc);
  150. X    }
  151. X    subj = subject_to(current_msg, Subject);
  152. X    if (do_set(set_options, "in_reply_to")) {
  153. X        (void) reply_to(current_msg, FALSE, buf);
  154. X        (void) sprintf(in_reply_to, "Message from %s", buf);
  155. X        if (p = header_field(current_msg, "date"))
  156. X        (void) strcat(in_reply_to, p);
  157. X    }
  158. X    }
  159. X    if (argv && *argv) {
  160. X    char buf[BUFSIZ];
  161. X    (void) argv_to_string(buf, argv);
  162. X    to = strcat(To, buf);
  163. X    }
  164. X    if (do_set(set_options, "auto_route"))
  165. X    improve_uucp_paths(To), improve_uucp_paths(Cc);
  166. X    /* if fortune is set, check to see if fortunates is set. If so,
  167. X     * check to see if the recipient is on the fortunates list.
  168. X     */
  169. X    if (do_set(set_options, "fortune")) {
  170. X    register char *p2 = do_set(set_options, "fortunates");
  171. X    if (!to || !p2 || *p2 && (chk_two_lists(to, p2, " \t,") ||
  172. X             (firstchar == 'r' && cc && chk_two_lists(cc, p2, " \t,"))))
  173. X        turnon(flgs, DO_FORTUNE);
  174. X    }
  175. X#ifdef SUNTOOL
  176. X    if (istool) {
  177. X    do_clear();
  178. X    panel_set(abort_item,   PANEL_SHOW_ITEM, TRUE,  0);
  179. X    panel_set(comp_item,    PANEL_SHOW_ITEM, FALSE, 0);
  180. X    panel_set(read_item,    PANEL_SHOW_ITEM, FALSE, 0);
  181. X    panel_set(respond_item, PANEL_SHOW_ITEM, FALSE, 0);
  182. X    }
  183. X#endif SUNTOOL
  184. X    return mail_someone(to, subj, cc, flgs, list);
  185. X}
  186. X
  187. X#ifdef SUNTOOL
  188. X/* panel item selection -- it's here because of local (static) variables */
  189. Xabort_mail(item, value)
  190. XPanel_item item;
  191. X{
  192. X    get_hdr_field = 0;
  193. X    if (item == abort_item && value != 2) {
  194. X    print("Aborted letter.");
  195. X    killme = 1, rm_edfile(SIGINT);
  196. X    flags = 0;
  197. X    }
  198. X    panel_set(comp_item,    PANEL_SHOW_ITEM, TRUE,  0);
  199. X    panel_set(send_item,    PANEL_SHOW_ITEM, FALSE, 0);
  200. X    panel_set(edit_item,    PANEL_SHOW_ITEM, FALSE, 0);
  201. X    panel_set(abort_item,   PANEL_SHOW_ITEM, FALSE, 0);
  202. X    panel_set(read_item,    PANEL_SHOW_ITEM, TRUE,  0);
  203. X    panel_set(respond_item, PANEL_SHOW_ITEM, TRUE,  0);
  204. X    unlock_cursors();
  205. X}
  206. X#endif SUNTOOL
  207. X
  208. Xmail_someone(to, subject, cc, flgs, list)
  209. Xregister char *to, *subject, *cc, *list;
  210. X{
  211. X    register char *p;
  212. X
  213. X    flags = flgs;
  214. X#ifdef SUNTOOL
  215. X    if (istool)
  216. X    rite(_tty.sg_kill), do_clear(), wprint("To: ");
  217. X#endif SUNTOOL
  218. X    if (to && *to) {
  219. X    if (!*To)
  220. X        (void) strcpy(To, to);
  221. X    if (istool)
  222. X        wprint("%s\n", To);
  223. X    } else
  224. X#ifdef SUNTOOL
  225. X    if (istool)
  226. X        turnon(get_hdr_field, TO_FIELD);
  227. X    else
  228. X#endif SUNTOOL
  229. X        to = NO_STRING;
  230. X    if (subject && *subject) {
  231. X    if (!*Subject)
  232. X        (void) strcpy(Subject, subject);
  233. X    if (istool)
  234. X        wprint("Subject: %s\n", Subject);
  235. X    } else
  236. X#ifdef SUNTOOL
  237. X    if (istool && !*Subject)
  238. X        turnon(get_hdr_field, SUBJECT);
  239. X    else
  240. X#endif SUNTOOL
  241. X        subject = NO_STRING;
  242. X    if (cc && *cc) {
  243. X    if (!*Cc)
  244. X        (void) strcpy(Cc, cc);
  245. X    if (istool)
  246. X        wprint("Cc: %s\n", Cc);
  247. X    } else
  248. X#ifdef SUNTOOL        /* get_hdr_field -- prevents prompting on replies */
  249. X    if (istool && get_hdr_field && do_set(set_options, "askcc"))
  250. X        turnon(get_hdr_field, CC_FIELD);
  251. X    else
  252. X#endif SUNTOOL
  253. X        cc = NO_STRING;
  254. X
  255. X    if (ison(glob_flags, REDIRECT)) {
  256. X    send_it(); /* doesn't return */
  257. X    return 0;
  258. X    }
  259. X    /* if (!*to) then prompting will be done */
  260. X    if (!istool) {
  261. X    if (!(p = set_header("To: ", to, !*to)) || !*p) {
  262. X        puts("No recipients, can't mail.");
  263. X        return -1;
  264. X    }
  265. X    (void) strcpy(To, p);
  266. X    if (p = set_header("Subject: ", subject, !*subject))
  267. X        (void) strcpy(Subject, p);
  268. X    if (*Cc)
  269. X        printf("Cc: %s\n", Cc);
  270. X    putchar('\n');
  271. X    }
  272. X#ifdef SUNTOOL
  273. X      else if (!get_hdr_field) {
  274. X    panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  275. X    panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  276. X    }
  277. X#endif SUNTOOL
  278. X    return start_file(list);
  279. X}
  280. X
  281. Xstart_file(list)
  282. Xchar *list;
  283. X{
  284. X    register char  *home;
  285. X    register int   i;
  286. X    char         line[256];
  287. X
  288. X    if (!(home = do_set(set_options, "home")) || !*home)
  289. X    home = ALTERNATE_HOME;
  290. X    (void) mktemp(sprintf(edfile, "%s/%s", home, EDFILE));
  291. X    {
  292. X    int omask = umask(077);
  293. X    fp = fopen(edfile, "w+");
  294. X    (void) umask(omask);
  295. X    if (!fp) {
  296. X#ifdef SUNTOOL
  297. X        if (istool)
  298. X        abort_mail(NO_ITEM, 0);
  299. X#endif SUNTOOL
  300. X        error("can't create %s", edfile);
  301. X        return -1;
  302. X    }
  303. X    }
  304. X    if (!istool) {
  305. X    oldint = signal(SIGINT, rm_edfile);
  306. X    oldquit = signal(SIGQUIT, rm_edfile);
  307. X    oldterm = signal(SIGTERM, rm_edfile);
  308. X    }
  309. X    oldhup = signal(SIGHUP, rm_edfile);
  310. X
  311. X    /* if flags call for it, include current message (with header?) */
  312. X    if (ison(flags, INCLUDE) || ison(flags,FORWARD) || ison(flags,INCLUDE_H)) {
  313. X    long copy_flgs = 0, is_forw = ison(flags, FORWARD);
  314. X    char buf[256];
  315. X    if (!is_forw)
  316. X        turnon(copy_flgs, INDENT);
  317. X    if (ison(flags, INCLUDE))
  318. X        turnon(copy_flgs, NO_HEADER);
  319. X    if (ison(flags, INCLUDE) || ison(flags, FORWARD))
  320. X        turnon(copy_flgs, NO_IGNORE);
  321. X#ifdef SUNTOOL
  322. X        if (istool)
  323. X            lock_cursors();
  324. X#endif SUNTOOL
  325. X    for (i = 0; i < msg_cnt; i++)
  326. X        if (msg_bit(list, i)) {
  327. X        if (is_forw) {
  328. X            (void) reply_to(i, FALSE, buf);
  329. X            fprintf(fp, "--- Forwarded mail from %s\n\n", buf);
  330. X        }
  331. X        wprint("%sing message %d ...",
  332. X            is_forw? "forward" : "includ", i+1);
  333. X        wprint("(%d lines)\n", copy_msg(i, fp, copy_flgs));
  334. X        set_isread(i); /* if we included it, we read it, right? */
  335. X        if (is_forw)
  336. X            fprintf(fp,"\n--- End of forwarded message from %s.\n",buf);
  337. X        }
  338. X    fflush(fp);
  339. X#ifdef SUNTOOL
  340. X    if (istool)
  341. X        unlock_cursors();
  342. X#endif SUNTOOL
  343. X    }
  344. X    if (ison(glob_flags, WARNING)) {
  345. X    if (escape && *escape != DEF_ESCAPE[0])
  346. X        wprint("(escape character is set to `%c')\n", *escape);
  347. X    }
  348. X    turnon(glob_flags, IS_GETTING);
  349. X#ifdef SUNTOOL
  350. X    /* enter editor if autoedit and replying to mail */
  351. X    if (istool && get_hdr_field)
  352. X    turnoff(flags, EDIT);
  353. X#endif SUNTOOL
  354. X    /* do an "if" again in case editor not found and EDIT turned off */
  355. X    if (ison(flags, EDIT)) {
  356. X    char *argv[3];
  357. X    argv[0] = (visual)? visual : editor;
  358. X    argv[1] = edfile;
  359. X    argv[2] = NULL;
  360. X    print("Starting \"%s\"...\n", argv[0]);
  361. X    in_editor = 1;
  362. X    execute(argv);
  363. X    in_editor = 0;
  364. X    turnoff(flags, EDIT);
  365. X    /* upon exit of editor, user must now type ^D or "." to send */
  366. X    if (istool)
  367. X        return 0;
  368. X    fflush(fp), (void) fseek(fp, 0L, 2);
  369. X    puts("continue editing letter or ^D to send");
  370. X    }
  371. X#ifdef SUNTOOL
  372. X    if (istool) {
  373. X    pw_char(msg_win, txt.x,txt.y, PIX_SRC^PIX_DST, fonts[curfont], '_');
  374. X    win_setcursor(msg_sw->ts_windowfd, &write_cursor);
  375. X    return 0;
  376. X    }
  377. X#endif SUNTOOL
  378. X    i = 0;
  379. X    do  {
  380. X    /* If the user hits ^C in cbreak mode, mush will return to
  381. X     * Getstr and not clear the buffer. whatever is typed next will
  382. X     * be appended to the line.  jumping here will force the line to
  383. X     * be cleared cuz it's a new call.
  384. X     */
  385. X    (void) setjmp(cntrl_c_buf);
  386. X    while (Getstr(line, 256, 0) > -1)
  387. X        if ((i = add_to_letter(line)) <= 0)
  388. X        break;
  389. X    } while (i >= 0 && !finish_up_letter());
  390. X    return 0;
  391. X}
  392. X
  393. Xchar *tilde_commands[] = {
  394. X    "commands: [OPTIONAL argument]",
  395. X    "e [editor]\tEnter editor. Editor used: \"set editor\", env EDITOR, vi",
  396. X    "v [editor]\tEnter visual editor. \"set visual\", env VISUAL, vi",
  397. X    "p [pager]\tPage message; pager used: \"set pager\", env. PAGER, more",
  398. X    "i [msg#'s]\tInclude current msg body [msg#'s] indented by \"indent_str\"",
  399. X    "H [msg#'s]\tSame, but include the message headers from included messages",
  400. X    "f [msg#'s]\tForward mail. Not indented, but marked as \"forwarded mail\"",
  401. X    "t [list]\tChange list of recipients",
  402. X    "s [subject]\tModify [set] subject header",
  403. X    "c [cc list]\tModify [set] carbon copy recipients",
  404. X    "b [bcc list]\tModify [set] blind carbon recipients",
  405. X    "h\t\tModify all message headers",
  406. X    "S[!]\t\tInclude Signature file [suppress file]",
  407. X    "F[!]\t\tAdd a fortune at end of letter [don't add]",
  408. X    "w file\t\tWrite msg buffer to file name",
  409. X    "a file\t\tAppend msg buffer to file name",
  410. X    "r file\t\tRead filename into message buffer",
  411. X    "q \t\tQuit message; save in dead.letter (unless \"nosave\" is set).",
  412. X    "x \t\tQuit message; don't save in dead.letter.",
  413. X    "$variable\tInsert the string value for \"variable\" into message.",
  414. X    ":cmd\t\tRun the mail command \"cmd\".",
  415. X    "u\t\tedit previous line in file.",
  416. X    "E\t\tErase message buffer; clear all contents of letter",
  417. X    0
  418. X};
  419. X
  420. Xadd_to_letter(line)
  421. Xregister char *line;
  422. X{
  423. X    register char *p;
  424. X    char buf[256];
  425. X
  426. X    killme = 0;
  427. X    (void) fseek(fp, 0L, 2); /* seek to end in case more was added by editor */
  428. X#ifdef SUNTOOL
  429. X    if (get_hdr_field) {
  430. X    /* These are received in order by design! */
  431. X    if (ison(get_hdr_field, TO_FIELD)) {
  432. X        if (!*line) {
  433. X            wprint("There must be a recipient!\nTo: ");
  434. X        return 1;
  435. X        }
  436. X        (void) strcpy(To, line), turnoff(get_hdr_field, TO_FIELD);
  437. X    } else if (ison(get_hdr_field, SUBJECT)) {
  438. X        (void) strcpy(Subject, line);
  439. X        turnoff(get_hdr_field, SUBJECT);
  440. X    } else if (ison(get_hdr_field, CC_FIELD)) {
  441. X        (void) strcpy(Cc, line);
  442. X        turnoff(get_hdr_field, CC_FIELD);
  443. X    } else if (ison(get_hdr_field, BC_FIELD)) {
  444. X        (void) strcpy(Bcc, line);
  445. X        turnoff(get_hdr_field, BC_FIELD);
  446. X    }
  447. X
  448. X        if (ison(get_hdr_field, SUBJECT))
  449. X        (void) set_header("Subject: ", Subject, 1);
  450. X        else if (ison(get_hdr_field, CC_FIELD))
  451. X        (void) set_header("Cc: ", Cc, 1);
  452. X        else if (ison(get_hdr_field, BC_FIELD))
  453. X        (void) set_header("Bcc: ", Bcc, 1);
  454. X    panel_set(send_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  455. X    panel_set(edit_item, PANEL_SHOW_ITEM, (get_hdr_field==0), 0);
  456. X    return 1;
  457. X    }
  458. X#endif SUNTOOL
  459. X    if (!strcmp(line, ".") && (istool || do_set(set_options, "dot")))
  460. X    return 0;
  461. X    if (*line != *escape) {
  462. X    fputs(line, fp), fputc('\n', fp), fflush(fp);
  463. X    return 1;
  464. X    }
  465. X    /* all commands are "~c" (where 'c' is the command). set p = first
  466. X     * character after 'c' and skip whitespace
  467. X     */
  468. X    p = line+2;
  469. X    skipspaces(0);
  470. X    switch (line[1]) {
  471. X    case 'v' : case 'p': case 'e':
  472. X        if (!*p || *p == 'i')
  473. X        p = (line[1] == 'p')? pager:
  474. X            (visual && line[1] == 'v')? visual: editor;
  475. X        if (line[1] == 'p') {
  476. X        wprint("To: %s\n", To);
  477. X        if (Subject[0])
  478. X            wprint("Subject: %s\n", Subject);
  479. X        if (Cc[0])
  480. X            wprint("Cc: %s\n", Cc);
  481. X        if (Bcc[0])
  482. X            wprint("Bcc: %s\n", Bcc);
  483. X        wprint("-----------\nMessage contains:\n");
  484. X        }
  485. X        if (line[1] == 'p' && (istool || !istool && lines_in(fp, crt))) {
  486. X        rewind(fp);
  487. X        while (fgets(buf, BUFSIZ, fp))
  488. X#ifdef SUNTOOL
  489. X            if (istool)
  490. X            Addstr(buf);
  491. X            else
  492. X#endif SUNTOOL
  493. X            (void) fputs(buf, stdout);
  494. X        } else {
  495. X        char *argv[3];
  496. X        argv[0] = p;
  497. X        argv[1] = edfile;
  498. X        argv[2] = NULL;
  499. X        in_editor = 1;
  500. X        execute(argv); /* page the message using pager */
  501. X        in_editor = 0;
  502. X        if (istool)
  503. X            return 1;
  504. X        }
  505. X    when '$': {
  506. X        register char *p2;
  507. X        if (!(p2 = do_set(set_options, p)))
  508. X        wprint("(%s isn't set)\n", p);
  509. X        else
  510. X        fprintf(fp, "%s\n", p2);
  511. X    }
  512. X    when ':': {
  513. X        char new[MAXMSGS_BITS];
  514. X        long save_flags = glob_flags;
  515. X
  516. X        turnon(glob_flags, IGN_SIGS);
  517. X        turnon(glob_flags, IGN_BANG);
  518. X        turnoff(glob_flags, DO_PIPE);
  519. X        turnoff(glob_flags, IS_PIPE);
  520. X        (void) cmd_line(p, new);
  521. X        glob_flags = save_flags;
  522. X#ifdef SUNTOOL
  523. X        if (istool && msg_pix) /* the command was to read a message */
  524. X        return 1;
  525. X#endif SUNTOOL
  526. X    }
  527. X    when 'i': case 'f': case 'H': case 'm': {
  528. X        int  n;
  529. X        long copy_flgs = 0;
  530. X        char list[MAXMSGS_BITS];
  531. X
  532. X        if (!msg_cnt) {
  533. X        print("No messages.\n");
  534. X        break;
  535. X        }
  536. X        clear_msg_list(list);
  537. X        if (line[1] != 'f')
  538. X        turnon(copy_flgs, INDENT);
  539. X        if (line[1] == 'i')
  540. X        turnon(copy_flgs, NO_HEADER);
  541. X        if (!*p)
  542. X        set_msg_bit(list, current_msg);
  543. X        else if (!do_range(p, list))
  544. X        return 1;
  545. X#ifdef SUNTOOL
  546. X        if (istool)
  547. X        lock_cursors();
  548. X#endif SUNTOOL
  549. X        for (n = 0; n < msg_cnt; n++)
  550. X        if (msg_bit(list, n)) {
  551. X            if (line[1] == 'f') {
  552. X            (void) reply_to(n, FALSE, buf);
  553. X            fprintf(fp, "--- Forwarded mail from %s\n\n", buf);
  554. X            }
  555. X            wprint("Including message %d ... ", n+1);
  556. X            wprint("(%d lines)\n", copy_msg(n, fp, copy_flgs));
  557. X            set_isread(n);
  558. X            if (line[1] == 'f')
  559. X        fprintf(fp, "\n--- End of forwarded message from %s\n\n", buf);
  560. X        }
  561. X#ifdef SUNTOOL
  562. X        if (istool)
  563. X        unlock_cursors();
  564. X#endif SUNTOOL
  565. X    }
  566. X    when 't':
  567. X#ifdef SUNTOOL
  568. X        if (!*p && istool) {
  569. X        turnon(get_hdr_field, TO_FIELD);
  570. X        (void) set_header("To: ", To, 1);
  571. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  572. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  573. X        return 1;
  574. X        }
  575. X#endif SUNTOOL
  576. X        /* ~t address   is a special case ... append to address */
  577. X        if (*p)
  578. X        (void) sprintf(To+strlen(To), " %s", p);
  579. X        else if (p = set_header("To: ", To, 1))
  580. X        if (!*p) {
  581. X            wprint("There must be a recipient!\n");
  582. X#ifdef SUNTOOL
  583. X            turnoff(get_hdr_field, TO_FIELD);
  584. X            panel_set(send_item, PANEL_SHOW_ITEM, TRUE, 0);
  585. X            panel_set(edit_item, PANEL_SHOW_ITEM, TRUE, 0);
  586. X#endif SUNTOOL
  587. X        } else
  588. X            (void) strcpy(To, p);
  589. X    when 's':
  590. X#ifdef SUNTOOL
  591. X        if (!*p && istool) {
  592. X        turnon(get_hdr_field, SUBJECT);
  593. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  594. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  595. X        (void) set_header("Subject: ", Subject, 1);
  596. X        return 1;
  597. X        }
  598. X#endif SUNTOOL
  599. X        if (*p || (p = set_header("Subject: ", Subject, 1)))
  600. X        if (!*p)
  601. X            Subject[0] = 0;
  602. X        else
  603. X            (void) strcpy(Subject, p);
  604. X    when 'c':
  605. X#ifdef SUNTOOL
  606. X        if (!*p && istool) {
  607. X        turnon(get_hdr_field, CC_FIELD);
  608. X        (void) set_header("Cc: ", Cc, 1);
  609. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  610. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  611. X        return 1;
  612. X        }
  613. X#endif SUNTOOL
  614. X        if (*p || (p = set_header("Cc: ", Cc, 1)))
  615. X        if (!*p)
  616. X            Cc[0] = 0;
  617. X        else
  618. X            (void) strcpy(Cc, p);
  619. X    when 'b':
  620. X#ifdef SUNTOOL
  621. X        if (!*p && istool) {
  622. X        turnon(get_hdr_field, BC_FIELD);
  623. X        (void) set_header("Bcc: ", Bcc, 1);
  624. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  625. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  626. X        return 1;
  627. X        }
  628. X#endif SUNTOOL
  629. X        if (*p || (p = set_header("Bcc: ", Bcc, 1)))
  630. X        if (!*p)
  631. X            Bcc[0] = 0;
  632. X        else
  633. X            (void) strcpy(Bcc, p);
  634. X    when 'h':
  635. X#ifdef SUNTOOL
  636. X        if (istool) {
  637. X        turnon(get_hdr_field, TO_FIELD);
  638. X        turnon(get_hdr_field, SUBJECT);
  639. X        turnon(get_hdr_field, CC_FIELD);
  640. X        turnon(get_hdr_field, BC_FIELD);
  641. X        (void) set_header("To: ", To, 1);
  642. X        panel_set(send_item, PANEL_SHOW_ITEM, FALSE, 0);
  643. X        panel_set(edit_item, PANEL_SHOW_ITEM, FALSE, 0);
  644. X        return 1;
  645. X        }
  646. X#endif SUNTOOL
  647. X        while ((p = set_header("To: ", To, 1)) && !*p)
  648. X        wprint("(There must be a recipient.)\n");
  649. X        (void) strcpy(To, p);
  650. X        if (p = set_header("Subject: ", Subject, 1))
  651. X        if (!*p)
  652. X            Subject[0] = 0;
  653. X        else
  654. X            (void) strcpy(Subject, p);
  655. X        if (p = set_header("Cc: ", Cc, 1))
  656. X        if (!*p)
  657. X            Cc[0] = 0;
  658. X        else
  659. X            (void) strcpy(Cc, p);
  660. X        if (p = set_header("Bcc: ", Bcc, 1))
  661. X        if (!*p)
  662. X            Bcc[0] = 0;
  663. X        else
  664. X            (void) strcpy(Bcc, p);
  665. X    when 'S':
  666. X        if (*p == '!')
  667. X        turnoff(flags, SIGN), wprint("not ");
  668. X        else
  669. X        turnon(flags, SIGN);
  670. X        wprint("adding signature file at end of message.\n");
  671. X    when 'F':
  672. X        if (*p == '!')
  673. X        turnoff(flags, DO_FORTUNE), wprint("not ");
  674. X        else
  675. X        turnon(flags, DO_FORTUNE);
  676. X        wprint("adding fortune at end of message.\n");
  677. X    when 'w': case 'a': case 'r':
  678. X        if (!*p) {
  679. X        wprint("(you must specify a filename)\n");
  680. X        return 1;
  681. X        }
  682. X        (void) fseek(fp, 0L, 2); /* append */
  683. X        file_to_fp(p, fp, (line[1] == 'r')? "r":
  684. X                  (line[1] == 'w')? "w": "a");
  685. X    /* go up one line in the message file and allow the user to edit it */
  686. X    when 'u': {
  687. X        long newpos, pos = ftell(fp);
  688. X        char oldline[256];
  689. X        if (istool) {
  690. X        wprint("(Not available in tool mode.)\n");
  691. X        return 1;
  692. X        }
  693. X        if (pos <= 0L) { /* pos could be -1 if ftell() failed */
  694. X        wprint("(No previous line in file.)\n");
  695. X        return 1;
  696. X        }
  697. X        /* get the last 256 bytes written and read backwards from the
  698. X         * current place until '\n' is found. Start by moving past the
  699. X         * first \n which is at the end of the line we want to edit
  700. X         */
  701. X        newpos = max(0, pos - 256);
  702. X        (void) fseek(fp, newpos, L_SET);
  703. X        /* don't fgets -- it'll stop at a \n */
  704. X        (void) read(fileno(fp), line, (int)(pos-newpos));
  705. X        pos--;
  706. X        /* the last char in line should be a \n cuz it was last input */
  707. X        if (line[(int)(pos-newpos)] != '\n')
  708. X        wprint("I don't know how, but your last line ended with %c.\n",
  709. X            line[(int)(pos-newpos)]);
  710. X        else
  711. X        line[(int)(pos-newpos)] = 0; /* null terminate \n for ^H-ing */
  712. X        for (pos--; pos > newpos && line[(int)(pos-newpos)] != '\n'; pos--)
  713. X        ;
  714. X        /* we've gone back to the end of the second previous line. Check
  715. X         * to see if the char we're pointing to is a \n.  It should be, but
  716. X         * if it's not, we moved back to the first line of the file.
  717. X         */
  718. X        if (line[(int)(pos-newpos)] == '\n')
  719. X        ++pos;
  720. X        /* save the old line that's there in case the user boo-boo's */
  721. X        (void) strcpy(oldline, line+(int)(pos-newpos));
  722. X        /* let set header print out the line and get the input */
  723. X        if (!(p = set_header("", line+(int)(pos-newpos), TRUE))) {
  724. X        wprint("Something bad happened and I don't know what it is.\n");
  725. X        p = oldline;
  726. X        } else if (*p == *escape && *++p != *escape) {
  727. X        wprint("(No %c escapes on %cu lines. Line unchanged.)\n",
  728. X                *escape, *escape);
  729. X        p = oldline;
  730. X        }
  731. X        /* seek to to the position where the new line will go */
  732. X        (void) fseek(fp, pos, L_SET);
  733. X        /* put the newly typed line */
  734. X        (void) fputs(p, fp); /* don't add \n in case padding is necessary */
  735. X        /* if the new line is less than the old line, we're going to do
  736. X         * one of two things.  The best thing to do is to truncate the
  737. X         * file to the end of the new line.  Sys-v can't do that, so we
  738. X         * pad the line with blanks.  May be messy in some cases, but...
  739. X         */
  740. X        if ((pos = strlen(p) - strlen(oldline)) < 0) {
  741. X#ifndef SYSV
  742. X        /* add the \n, flush the file, truncate to the current pos */
  743. X        fputc('\n', fp), fflush(fp);
  744. X        (void) ftruncate(fileno(fp), (int)ftell(fp));
  745. X#else
  746. X        /* pad with blanks to the length of the old line. add \n */
  747. X        while (pos++ < 0)
  748. X            fputc(' ', fp);
  749. X        fputc('\n', fp), fflush(fp);
  750. X#endif SYSV
  751. X        } else
  752. X        /* the new line is >= the old line, add \n -- no trunc req. */
  753. X            fputc('\n', fp);
  754. X        return 1;
  755. X     }
  756. X    /* break;  not here cuz of "return" (lint). */
  757. X    case 'E':
  758. X        wprint("Message buffer empty\n");
  759. X        if (emptyfile(&fp, edfile) == -1)
  760. X        error(edfile);
  761. X    when 'q':
  762. X        /* save in dead.letter if nosave not set -- rm_edfile(-2). */
  763. X        rm_edfile(-2); /* doesn't return out of tool mode */
  764. X        return -1;
  765. X        /* break; not stated cuz of "return" (lint) */
  766. X    case 'x':
  767. X        /* don't save dead.letter -- simulate normal rm_edfile() call */
  768. X        rm_edfile(0);
  769. X#ifdef SUNTOOL
  770. X        if (istool) {
  771. X        wprint("*Letter aborted*");
  772. X        pw_char(msg_win, txt.x,txt.y, PIX_CLR, fonts[curfont], '_');
  773. X        }
  774. X#endif SUNTOOL
  775. X        return -1;
  776. X        /* break; (not specified for lint) */
  777. X    default:
  778. X        if (line[1] == *escape) {
  779. X        fputs(line+1, fp), fputc('\n', fp), fflush(fp);
  780. X        return 1;
  781. X        } else {
  782. X        register int x;
  783. X        for (x = 0; tilde_commands[x]; x++)
  784. X            wprint("%s%s\n", escape, tilde_commands[x]);
  785. X        wprint("%s%s\t\tbegin a line with a single %s\n",
  786. X            escape, escape, escape);
  787. X#ifdef SUNTOOL
  788. X        if (istool)
  789. X            (void) help(0, "compose", tool_help);
  790. X#endif SUNTOOL
  791. X        }
  792. X    }
  793. X    (void) fseek(fp, 0L, 2); /* seek to end of file in case there's more */
  794. X    wprint("(continue editing letter)\n");
  795. X#ifdef SUNTOOL
  796. X    if (istool)
  797. X    pw_char(msg_win, txt.x,txt.y, PIX_SRC, fonts[curfont], '_');
  798. X#endif SUNTOOL
  799. X    return 1;
  800. X}
  801. X
  802. X/*
  803. X * finish up the letter. ask for the cc line, if verify is set, ask to
  804. X * verify sending, continue editing, or to dump the whole idea.
  805. X * Then check for signature and fortune.  Finally, pass it to send_it()
  806. X * to actually send it off.
  807. X */
  808. Xfinish_up_letter()
  809. X{
  810. X    register char *p;
  811. X    char buf[256];
  812. X
  813. X#ifdef SUNTOOL
  814. X    if (istool)
  815. X    lock_cursors();
  816. X    else
  817. X#endif SUNTOOL
  818. X    if (isoff(glob_flags, REDIRECT)) {
  819. X    if (do_set(set_options, "askcc") && (p = set_header("Cc: ", Cc, 1)))
  820. X        (void) strcpy(Cc, p);
  821. X    /* ~v on the Cc line asks for verification, first initialize p! */
  822. X    p = NULL;
  823. X    if (!strncmp(Cc, "~v", 2) || (p = do_set(set_options, "verify"))) {
  824. X        if (!p) /* so we don't Cc to ~v! */
  825. X        *Cc = 0;
  826. X        fprintf(stderr, "send, continue editing, discard [s,c,d]? ");
  827. X        if (Getstr(buf, 256, 0) < 0 || lower(*buf) == 'd') {
  828. X        rm_edfile(-2);
  829. X        return 1;
  830. X        } else if (lower(*buf) == 'c') {
  831. X        puts("(continue editing letter)");
  832. X        return 0;
  833. X        }
  834. X    }
  835. X    }
  836. X
  837. X    if (ison(flags, SIGN)) {
  838. X    char *home = do_set(set_options, "home");
  839. X    if (!home || !*home)
  840. X        home = ALTERNATE_HOME;
  841. X    if (!(p = do_set(set_options, "autosign")) || !*p)
  842. X        (void) sprintf(buf, "%s/%s", home, SIGNATURE);
  843. X    else
  844. X        (void) strcpy(buf, p);
  845. X    wprint("Signing letter... "), fflush(stdout);
  846. X    fputc('\n', fp), fflush(fp);
  847. X    (void) fseek(fp, 0L, 2); /* guarantee position at end of file */
  848. X    if (*buf == '$')
  849. X        if (!(p = do_set(set_options, buf)))
  850. X        wprint("(%s isn't set -- letter not signed)\n", buf);
  851. X        else
  852. X        fprintf(fp, "%s\n", p), wprint("\n"), fflush(fp);
  853. X    else if (*buf == '\\')
  854. X        fprintf(fp, "%s\n", buf+1), wprint("\n"), fflush(fp);
  855. X    else
  856. X        file_to_fp(buf, fp, "r");
  857. X    }
  858. X
  859. X    if (ison(flags, DO_FORTUNE)) {
  860. X    char     foo[256];
  861. X    FILE     *pp2;
  862. X    int     lines = 0;
  863. X
  864. X    wprint("You may be fortunate... "), fflush(stdout);
  865. X    if ((p = do_set(set_options, "fortune")) && *p == '/')
  866. X        (void) strcpy(foo, p);
  867. X    else
  868. X        (void) sprintf(foo, "%s %s", FORTUNE, (p && *p == '-')? p: "-s");
  869. X    if (!(pp2 = popen(foo, "r")))
  870. X        error(foo);
  871. X    else {
  872. X        turnon(glob_flags, IGN_SIGS);
  873. X        (void) fseek(fp, 0L, 2); /* go to end of file */
  874. X        while (fgets(foo, 256, pp2))
  875. X        fputs(foo, fp), lines++;
  876. X        (void) pclose(pp2);
  877. X        turnoff(glob_flags, IGN_SIGS);
  878. X        fflush(fp);
  879. X        wprint("added %d line%s\n", lines, lines == 1? "" : "s");
  880. X    }
  881. X    }
  882. X    send_it();
  883. X    turnoff(glob_flags, IS_GETTING);
  884. X    return 1;
  885. X}
  886. X
  887. X/*
  888. X * actually send the letter.
  889. X * 1. Reset all the signals because of fork.
  890. X * 2. determine recipients (users, address, files, programs)
  891. X * 3. Determine mailer, fork and return (if not verbose).
  892. X * 4. popen mailer, $record, and other files specified in step 1.
  893. X * 5. make the headers; this includes To: line, and user set hedaers, etc...
  894. X * 6. copy the letter right into the array of file pointers (step 1).
  895. X * 7. close the mailer and other files (step 1) and remove the edit-file.
  896. X */
  897. Xstatic void
  898. Xsend_it()
  899. X{
  900. X    register char *p;
  901. X#ifdef MAXFILES
  902. X    register int size = MAXFILES - 1;
  903. X    FILE *files[MAXFILES];
  904. X#else
  905. X    register int size = getdtablesize() - 1;
  906. X    FILE *files[30];  /* 30 should be sufficiently large enough */
  907. X#endif /* MAXFILES */
  908. X    int next_file = 1; /* reserve files[0] for the mail delivery program */
  909. X    char buf[3*BUFSIZ];
  910. X
  911. X    if (!istool) {
  912. X    (void) signal(SIGINT, oldint);
  913. X    (void) signal(SIGQUIT, oldquit);
  914. X    (void) signal(SIGTERM, oldterm);
  915. X    }
  916. X    (void) signal(SIGHUP, oldhup);
  917. X
  918. X#ifdef VERBOSE_ARG
  919. X    if (ison(flags, VERBOSE) || do_set(set_options, "verbose"))
  920. X    (void) sprintf(buf, "%s %s", MAIL_DELIVERY, VERBOSE_ARG);
  921. X    else
  922. X#endif VERBOSE_ARG
  923. X    (void) strcpy(buf, MAIL_DELIVERY);
  924. X#ifdef METOO_ARG
  925. X    if (do_set(set_options, "metoo"))
  926. X    (void) sprintf(buf+strlen(buf), " %s", METOO_ARG);
  927. X#endif METOO_ARG
  928. X
  929. X    /*
  930. X     * For alias expansion on To, Cc and Bcc lines, first expand the recipients
  931. X     * lists so that aliases are expanded.  Then detemine which items in the
  932. X     * list are files or programs and remove those from the list. Finally,
  933. X     * copy the resulting buffer back into the original To, Cc, and Bcc buffer.
  934. X     * rm_edfile(-2) will save in dead letter (only if "nosave" set) and
  935. X     * will long jump back to main loop if any alias expansions fail. Insure
  936. X     * a forced dead letter by rm_edfile(-1). But, rm_edfile will exit with -1
  937. X     * arg, so kludge by turning on the VERBOSE bit in "flags".
  938. X     */
  939. X    if (!(p = alias_to_address(To))) {
  940. X    print("address expansion failed for To: line.\n");
  941. X    turnon(flags, VERBOSE);
  942. X    rm_edfile(-1);
  943. X    } else {
  944. X    next_file += find_files(p, files+next_file, size - next_file);
  945. X    if (!*strcpy(To, p)) {
  946. X        print("There must be at least 1 legal recipient on the To line\n");
  947. X        while (--next_file > 1)
  948. X        fclose(files[next_file]);
  949. X        rm_edfile(-2);
  950. X        return;
  951. X    }
  952. X    }
  953. X    if (*Cc)
  954. X    if (!(p = alias_to_address(Cc))) {
  955. X        print("address expansion failed for Cc: line.\n");
  956. X        turnon(flags, VERBOSE);
  957. X        while (--next_file > 1)
  958. X        fclose(files[next_file]);
  959. X        rm_edfile(-1);
  960. X    } else {
  961. X        next_file += find_files(p, files+next_file, size - next_file);
  962. X        (void) strcpy(Cc, p);
  963. X    }
  964. X    if (*Bcc)
  965. X    if (!(p = alias_to_address(Bcc))) {
  966. X        print("address expansion failed for Bcc: line.\n");
  967. X        turnon(flags, VERBOSE);
  968. X        while (--next_file > 1)
  969. X        fclose(files[next_file]);
  970. X        rm_edfile(-1);
  971. X    } else {
  972. X        next_file += find_files(p, files+next_file, size - next_file);
  973. X        (void) strcpy(Bcc, p);
  974. X    }
  975. X
  976. X    /*
  977. X     * build the mailer's "command line" -- we build our own headers later.
  978. X     * the mailer will mail to everyone listed.  The headers will contain
  979. X     * the to and cc lines  -- Bcc is never printed.
  980. X     */
  981. X    (void) sprintf(buf+strlen(buf), " %s %s %s", To, Cc, Bcc);
  982. X
  983. X#ifdef SYSV
  984. X    /*
  985. X     * Sys-v does not recover from SIGCLD elegantly. That is, all system calls
  986. X     * return -1 and does not complete whatever it was doing when the signal
  987. X     * gets delievered -- we could be reading from stdin, a file, or feeding
  988. X     * to a pager -- this isn't good.  I'm not good enough at SYSV to know how
  989. X     * to recover from this correctly.  BSD systems recover elegantly and
  990. X     * deliver the sigchld properly.
  991. X     */
  992. X    turnon(flags, VERBOSE);
  993. X#endif SYSV
  994. X
  995. X    Debug("mail command: %s\n", buf);
  996. X
  997. X#ifdef SUNTOOL
  998. X    if (istool)
  999. X    abort_mail(NO_ITEM, 0);
  1000. X#endif SUNTOOL
  1001. X
  1002. X    if (isoff(flags, VERBOSE) && debug < 3)
  1003. X    switch (fork()) {
  1004. X        case  0:  /* the child will send the letter. ignore signals */
  1005. X        (void) signal(SIGINT, SIG_IGN);
  1006. X        (void) signal(SIGHUP, SIG_IGN);
  1007. X        (void) signal(SIGQUIT, SIG_IGN);
  1008. X        (void) signal(SIGTERM, SIG_IGN);
  1009. X#ifdef SIGCONT
  1010. X        (void) signal(SIGCONT, SIG_IGN);
  1011. X        (void) signal(SIGTSTP, SIG_IGN);
  1012. X#endif SIGCONT
  1013. X        turnon(glob_flags, IGN_SIGS);
  1014. X        break;
  1015. X        case -1:
  1016. X        error("fork failed trying to send mail");
  1017. X        default:
  1018. X        if (isoff(glob_flags, REDIRECT))
  1019. X            fclose(fp);
  1020. X#ifdef SUNTOOL
  1021. X                if (istool) {
  1022. X            wprint("Letter sent.");
  1023. X            print("Letter sent.");
  1024. X            pw_char(msg_win, txt.x,txt.y, PIX_CLR, fonts[curfont], '_');
  1025. X        }
  1026. X#endif SUNTOOL
  1027. X        while (--next_file > 0)
  1028. X            fclose(files[next_file]);
  1029. X        return;
  1030. X    }
  1031. X
  1032. X    if (debug > 2)
  1033. X    files[0] = stdout;
  1034. X    else if (!(files[0] = open_file(buf, TRUE))) {
  1035. X    rm_edfile(-1); /* force saving of undeliverable mail */
  1036. X    return;
  1037. X    }
  1038. X
  1039. X    if (ison(flags, VERBOSE))
  1040. X    wprint("Sending letter ... "), fflush(stdout);
  1041. X
  1042. X    /* see if record is set.  If so, open that file for appending and add
  1043. X     * the letter in a format such that mail can be read from it
  1044. X     */
  1045. X    if (p = do_set(set_options, "record")) {
  1046. X    if (!*p)
  1047. X        p = "~/record";
  1048. X    (void) strcpy(buf, p);
  1049. X    next_file += find_files(buf, files+next_file, size - next_file);
  1050. X    }
  1051. X
  1052. X    /* don't send this to Sendmail --make folders conform to RFC-822 */
  1053. X    for (size = 1; size < next_file; size++)
  1054. X    if (files[size]) {
  1055. X        time_t t;
  1056. X        (void) time(&t);
  1057. X        fprintf(files[size], "From %s %s", login, ctime(&t));
  1058. X        fprintf(files[size], "From: %s\n", login);
  1059. X        fprintf(files[size], "Date: %s", ctime(&t));
  1060. X        fprintf(files[size], "Status: OR\n");
  1061. X    }
  1062. X
  1063. X    /* first print users own message headers */
  1064. X    if (own_hdrs && !do_set(set_options, "no_hdrs")) {
  1065. X    struct options *opts;
  1066. X    for (opts = own_hdrs; opts; opts = opts->next)
  1067. X        for (size = 0; size < next_file; size++)
  1068. X        fprintf(files[size], "%s %s\n", opts->option, opts->value);
  1069. X    }
  1070. X
  1071. X    /* send the header stuff to sendmail and end header with a blank line */
  1072. X    if (*in_reply_to)
  1073. X    for (size = 0; size < next_file; size++)
  1074. X        fprintf(files[size], "In-Reply-To: %s\n", in_reply_to);
  1075. X    for (size = 0; size < next_file; size++)
  1076. X    fprintf(files[size], "X-Mailer: %s\n", VERSION);
  1077. X    for (size = 0; size < next_file; size++)
  1078. X    fprintf(files[size], "To: %s\n", To);
  1079. X    if (*Subject)
  1080. X    for (size = 0; size < next_file; size++)
  1081. X        fprintf(files[size], "Subject: %s\n", Subject);
  1082. X    if (*Cc)
  1083. X    for (size = 0; size < next_file; size++)
  1084. X        fprintf(files[size], "Cc: %s\n", Cc);
  1085. X
  1086. X    for (size = 0; size < next_file; size++)
  1087. X    fputc('\n', files[size]);
  1088. X
  1089. X    /* if redirection, fp = stdin, else rewind the file just made */
  1090. X    if (isoff(glob_flags, REDIRECT))
  1091. X    rewind(fp);
  1092. X    else
  1093. X    fp = stdin;
  1094. X
  1095. X    /* read from stdin or the edfile till EOF and send it all to the mailer */
  1096. X    while (fgets(buf, BUFSIZ, fp))
  1097. X    for (size = 0; size < next_file; size++) {
  1098. X        if (!strncmp(buf, "From ", 5))
  1099. X        fputc('>', files[size]);
  1100. X        fputs(buf, files[size]);
  1101. X    }
  1102. X
  1103. X    for (size = 1; size < next_file; size++)
  1104. X    if (files[size])
  1105. X        fclose(files[size]); /* if it was popened, sigchld will close it */
  1106. X
  1107. X    rm_edfile(0);
  1108. X    if (debug < 3)
  1109. X    (void) pclose(files[0]);
  1110. X
  1111. X    if ((ison(flags, VERBOSE) || debug > 2) && isoff(glob_flags, REDIRECT))
  1112. X    wprint("sent.\n");
  1113. X    else
  1114. X    exit(0); /* not a user exit -- a child exit */
  1115. X}
  1116. X
  1117. X/* ARGSUSED */
  1118. Xrm_edfile(sig)
  1119. X{
  1120. X    if (sig > 0 && !killme) {
  1121. X    (void) signal(sig, rm_edfile);
  1122. X    killme = 1;
  1123. X    wprint("\n** interrupt -- one more to kill letter **\n");
  1124. X#ifdef SUNTOOL
  1125. X    if (istool) {
  1126. X        pw_char(msg_win, txt.x,txt.y, PIX_SRC, fonts[curfont], '_');
  1127. X        return;
  1128. X    }
  1129. X#endif SUNTOOL
  1130. X    longjmp(cntrl_c_buf, 1);
  1131. X    }
  1132. X    in_editor = killme = 0;
  1133. X    /* if sig == -1, force a save into dead.letter.
  1134. X     * else, check for nosave not being set and save anyway if it's not set
  1135. X     * sig == 0 indicates normal exit (or ~x), so don't save a dead letter.
  1136. X     */
  1137. X    if (sig == -1 || sig != 0 && !do_set(set_options, "nosave")) 
  1138. X    dead_letter();
  1139. X    if (isoff(glob_flags, REDIRECT))
  1140. X    fclose(fp);
  1141. X    (void) unlink(edfile);
  1142. X
  1143. X    if (sig == -1 && isoff(flags, VERBOSE) && debug < 3)
  1144. X    exit(-1);
  1145. X
  1146. X    turnoff(glob_flags, IS_GETTING);
  1147. X#ifdef SUNTOOL
  1148. X    if (sig && istool > 1) {
  1149. X    wprint("*Letter aborted*");
  1150. X    abort_mail(abort_item, 2);
  1151. X    }
  1152. X#endif SUNTOOL
  1153. X
  1154. X    if (sig == SIGHUP)
  1155. X    cleanup(0);
  1156. X    (void) signal(SIGHUP, oldhup);
  1157. X    if (!istool) {
  1158. X    (void) signal(SIGINT, oldint);
  1159. X    (void) signal(SIGQUIT, oldquit);
  1160. X    (void) signal(SIGTERM, oldterm);
  1161. X    }
  1162. X
  1163. X    if (sig == 0)
  1164. X    return;
  1165. X    if (istool || sig == -2) /* make sure sigchld is reset first */
  1166. X    return;
  1167. X
  1168. X    if (isoff(glob_flags, DO_SHELL)) {  /* If we're not in a shell, exit */
  1169. X    puts("exiting");
  1170. X    echo_on();
  1171. X    exit(1);
  1172. X    }
  1173. X    longjmp(jmpbuf, 1);
  1174. X}
  1175. X
  1176. X/* save letter into dead letter */
  1177. Xdead_letter()
  1178. X{
  1179. X    char     *p, buf[BUFSIZ];
  1180. X    long     t;
  1181. X    FILE     *dead;
  1182. X
  1183. X    if (ison(glob_flags, REDIRECT)) {
  1184. X    print("input redirected -- can't save dead letter.\n");
  1185. X    return;
  1186. X    }
  1187. X    /* don't save a dead letter if there's nothing to save. */
  1188. X    if (fseek(fp, 0L, 2) || ftell(fp) == 0L)
  1189. X    return;
  1190. X    if (!(p = do_set(set_options, "dead")))
  1191. X    p = "~/dead.letter";
  1192. X    if (!(dead = open_file(p, FALSE)))
  1193. X    return;
  1194. X    (void) time (&t);
  1195. X    fflush(fp);
  1196. X    rewind(fp);
  1197. X    fprintf(dead, "Unfinished letter from %s", ctime(&t));
  1198. X    fprintf(dead, "To: %s\nSubject: %s\nCc: %s\n", To, Subject, Cc);
  1199. X    while(fgets(buf, BUFSIZ, fp))
  1200. X    (void) fputs(buf, dead);
  1201. X    (void) fputc('\n', dead);
  1202. X    (void) fclose(dead);
  1203. X    print("Saved unfinished letter in %s.\n", p);
  1204. X}
  1205. END_OF_FILE
  1206. if test 35676 -ne `wc -c <'mail.c'`; then
  1207.     echo shar: \"'mail.c'\" unpacked with wrong size!
  1208. fi
  1209. # end of 'mail.c'
  1210. fi
  1211. echo shar: End of archive 10 \(of 12\).
  1212. cp /dev/null ark10isdone
  1213. MISSING=""
  1214. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  1215.     if test ! -f ark${I}isdone ; then
  1216.     MISSING="${MISSING} ${I}"
  1217.     fi
  1218. done
  1219. if test "${MISSING}" = "" ; then
  1220.     echo You have unpacked all 12 archives.
  1221.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1222. else
  1223.     echo You still need to unpack the following archives:
  1224.     echo "        " ${MISSING}
  1225. fi
  1226. ##  End of shell archive.
  1227. exit 0
  1228.